#coding=utf-8

from copy import deepcopy

# Matrix methods

class Matrix(object):
    
    def __init__(self, list_of_lists):
        self.nrows = len(list_of_lists)
        if self.nrows == 0:
            raise ValueError("Una matriz debe ser de tamaño al menos 1x1")
        self.ncols = len(list_of_lists[0])
        if self.ncols == 0:
            raise ValueError("Una matriz debe ser de tamaño al menos 1x1")
        for row in list_of_lists:
            if len(row) != self.ncols:
                raise ValueError("Todas las filas de la matriz deben ser "
                                 "del mismo largo")
        self.matrix = list_of_lists
    
    def __repr__(self):        
        str_row = ""
        for i in range(0,self.nrows):
            for j in range(0, self.ncols-1):
                str_row += str(self.get((i,j))) + "  "
            str_row += str(self.get((i,self.ncols-1))) + "\n"
        return str_row
    
    def __getitem__(self, index):
        return deepcopy(self.matrix[index])
    
    def __iter__(self):
        list_of_lists = deepcopy(self.matrix)
        return iter(list_of_lists)
    
    # Needed to make matrix hashable
    def __eq__(self, other):
        return self.matrix == other.matrix
    
    # Needed to make matrix hashable
    def __ne__(self, other):
        return self.matrix != other.matrix
    
    def copy(self):
        list_of_lists = deepcopy(self.matrix)
        return Matrix(list_of_lists)
    
    def get(self, tuple):
        if len(tuple) != 2:
            raise ValueError("La matriz es de dos dimensiones y la tupla "
                             "tiene longitud {len}".format(len=len(tuple)))
        return self.matrix[tuple[0]][tuple[1]]
    
    def set(self, tuple, val):
        if len(tuple) != 2:
            raise ValueError("La matriz es de dos dimensiones y la tupla "
                             "tiene longitud {len}".format(len=len(tuple)))
        self.matrix[tuple[0]][tuple[1]] = val
    
    def index(self, obj):
        return self.matrix.index(obj)


def zero_index(matriz):
    for l in matriz:
        if 0 in l:
            return (matriz.index(l), l.index(0))
    #if there is no 0, raises an error
    raise ValueError("La matriz no contiene un cero")
    
def interchange(matrix,p1,p2):
    """
    Returns a copy of the matrix argument with element of position
    p1 switched with the element on position p2
    """
    matriz = matrix.copy()
    val1 = matriz.get(p1)
    val2 = matriz.get(p2)
    matriz.set(p1, val2)
    matriz.set(p2, val1)
    return matriz
